package com.hilin.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.util.DigestUtils;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author qhl
 */
@Slf4j
public class RequestUtils {

    public static final MediaType MEDIA_TYPE_APPLICATION_JSON = MediaType.parse("application/json");
    public static final MediaType MEDIA_TYPE_TEXT_PLAIN = MediaType.parse("text/plain");

    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectionPool(new ConnectionPool(20, 1, TimeUnit.MINUTES))
            .writeTimeout(15, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .connectTimeout(15, TimeUnit.SECONDS)
            .build();

    /**
     * post提交
     *
     * @param url
     * @param mediaType
     * @param body
     * @param header
     * @return
     */
    public static String post(String url, MediaType mediaType, String body, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .post(RequestBody.create(mediaType, body))
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  mediaType:{}  header:{}  body:{}  result:{}", url, mediaType.toString(), header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  mediaType:{}  header:{}  body:{}", url, mediaType.toString(), header, body);
            }
        }
        return result;
    }

    /**
     * put提交
     *
     * @param url
     * @param mediaType
     * @param body
     * @param header
     * @return
     */
    public static String put(String url, MediaType mediaType, String body, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .put(RequestBody.create(mediaType, body))
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  mediaType:{}  header:{}  body:{}  result:{}", url, mediaType.toString(), header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  mediaType:{}  header:{}  body:{}", url, mediaType.toString(), header, body);
            }
        }
        return result;
    }

    /**
     * put提交
     *
     * @param url
     * @param header
     * @return
     */
    public static String delete(String url, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .delete()
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  header:{}  result:{}", url, header, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  header:{}  ", url, header);
            }
        }
        return result;
    }

    /**
     * post提交
     *
     * @param url
     * @param body
     * @param header
     * @return
     */
    public static String postForm(String url, Map<String, String> header, Map<String, String> body) {
        boolean isSuccess = false;
        String result = null;
        try {
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            if (body != null) {
                body.forEach(bodyBuilder::add);
            }
            Request.Builder builder = new Request.Builder()
                    .post(bodyBuilder.build())
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
            return result;
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  header:{}  body:{}  result:{}", url, header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  header:{}  body:{}", url, header, body);
            }
        }
        return result;
    }

    /**
     * get提交
     */
    public static String get(String url, Map<String, String> header) {
        try {
            Request.Builder builder = new Request.Builder()
                    .get()
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            return response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
        }
        return null;
    }

    /**
     * 摘要认证请求
     *
     * @param user
     * @param password
     * @param url
     * @param json
     * @return
     * @throws Exception
     */
    public static String postJsonDigestAuth(String user, String password, String url, String json) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("[网络请求]接口开始访问: user = {} , password = {} , url = {} , json = {}", user, password, url, json);
        }
        String uri = new URL(url).getPath();
        Response response = CLIENT.newCall(new Request.Builder()
                .get().url(url)
                .build()).execute();
        if (response.code() != 401) {
            return null;
        }
        String wwwAuth = response.header("WWW-Authenticate");
        String realm = wwwAuth.split("realm=\"")[1].split("\"")[0];
        String qop = wwwAuth.split("qop=\"")[1].split("\"")[0];
        String nonce = wwwAuth.split("nonce=\"")[1].split("\"")[0];
        String opaque = wwwAuth.split("opaque=\"")[1].split("\"")[0];
        String nc = "00000001";
        response.close();
        String cn = "" + System.currentTimeMillis();
        String ha1 = DigestUtils.md5DigestAsHex((user + ":" + realm + ":" + password).getBytes());
        String ha2 = DigestUtils.md5DigestAsHex(("POST" + ":" + uri).getBytes());
        String resp = ha1 +
                ":" + nonce +
                ":" + nc +
                ":" + cn +
                ":" + qop +
                ":" + ha2;
        String respEncodeStr = DigestUtils.md5DigestAsHex(resp.getBytes());

        StringBuilder sb = new StringBuilder();
        sb.append("Digest ");
        sb.append("username=\"").append(user).append("\",");
        sb.append("realm=\"").append(realm).append("\",");
        sb.append("nonce=\"").append(nonce).append("\",");
        sb.append("uri=\"").append(uri).append("\",");
        sb.append("cnonce=\"").append(cn).append("\",");
        sb.append("nc=\"").append(nc).append("\",");
        sb.append("algorithm=\"").append("MD5").append("\",");
        sb.append("response=\"").append(respEncodeStr).append("\",");
        sb.append("qop=\"").append(qop).append("\",");
        sb.append("opaque=\"").append(opaque).append("\"");
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", sb.toString());
        String result = post(
                url,
                MEDIA_TYPE_APPLICATION_JSON,
                json,
                headers
        );
        if (log.isInfoEnabled()) {
            log.info("[网络请求]接口访问结束: \nuser = {}\npassword = {}\nurl = {}\njson = {}\nresult = {}", user, password, url, json, result);
        }
        return result;
    }

    public static void main(String[] args) {
        String body = String.format("{\"id\":\"%s\",\"include_neighbors\":true,\"is_freelyread\":true}", "156849");
        String str = post("https://time.geekbang.org/serv/v1/article", MEDIA_TYPE_APPLICATION_JSON,
                body
                , MapUtils.getInstanceStringString()
                        .put("Content-Length", "" + body.getBytes().length)
                        .put("Accept", "*/*")
                        .put("Cookie", "LF_ID=1639738612990-3907430-7564279; _ga=GA1.2.1642356764.1639738613; gk_exp_uid=NTBmMjUyNjIzN2FiMTVkYzk4MmJjNmNmY2M4YTIzYmU=|1639739881648559129|45c85c440fad96affee66842723138bc7231230ee2c6c6c958a80236d30791b8; GCID=8a6214b-3b78ad7-f4a1a1c-2ec5999; GRID=8a6214b-3b78ad7-f4a1a1c-2ec5999; gksskpitn=004a15c6-be2a-4b0d-a8b9-d4383d0f1544; _gid=GA1.2.1752903204.1639983118; GCESS=BgQEAC8NAAEIINErAAAAAAADBCEowGECBCEowGELAgYACgQAAAAACAEDCQEBBQQAAAAADQEBBgScjxkGBwR481axDAEB; Hm_lvt_59c4ff31a9ee6263811b23eb921a5083=1639739819,1639740676,1639983118,1639983139; MEIQIA_TRACK_ID=22XUOsHMFmIPjX0gsgNJCA5PJOz; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%222871584%22%2C%22first_id%22%3A%2217dc8099b5572e-0dc7cfd310ab0e-3e604809-2073600-17dc8099b56979%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_landing_page%22%3A%22https%3A%2F%2Fu.geekbang.org%2F%22%2C%22%24latest_utm_source%22%3A%22u_nav_web%22%2C%22%24latest_utm_medium%22%3A%22u_nav_web%22%2C%22%24latest_utm_term%22%3A%22u_nav_web%22%7D%2C%22%24device_id%22%3A%2217dc8099b5572e-0dc7cfd310ab0e-3e604809-2073600-17dc8099b56979%22%7D; MEIQIA_VISIT_ID=22XsUXFp1kQPbxi6QCFnxtzdTeu; Hm_lvt_022f847c4e3acd44d4a2481d9187f1e6=1639740676,1639983119,1639983139,1639995292; _gat=1; SERVERID=3431a294a18c59fc8f5805662e2bd51e|1639996523|1639995292; Hm_lpvt_022f847c4e3acd44d4a2481d9187f1e6=1639996523; gk_process_ev={%22referrer%22:%22https://time.geekbang.org/%22%2C%22utime%22:1639996477664%2C%22count%22:5%2C%22referrerTarget%22:%22%22%2C%22target%22:%22%22}; Hm_lpvt_59c4ff31a9ee6263811b23eb921a5083=1639996523")
                        .put("Host", "time.geekbang.org")
                        .put("Origin", "https://time.geekbang.org")
                        .put("Referer", "https://time.geekbang.org/column/article/155444")
                        .put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36")
                        .put("Content-Type", "application/json;charset=utf-8")
//                        .put("Accept-Encoding","gzip, deflate, br")
//                        .put("Accept-Encoding","gzip, deflate, br")
                        .put("Connection","keep-alive")
                        .build());
        System.out.println(str);
        JSONObject object = JSON.parseObject(str);
        System.out.println(object.getJSONObject("data").getString("article_title") + " : " + object.getJSONObject("data").getString("audio_download_url"));

    }

}
